PostgreSQL 不支持的 O_DIRECT,MySQL 和 Oracle 都有
破产码农
在 MySQL 数据库中,几乎默认会将 InnoDB 的脏页刷新参数 innodb_flush_method 设置为 O_DIRECT ,以此提升数据库的磁盘刷新性能。
Oracle 数据库也有提供了参数 FILESYTEMIO_OPTIONS 可将刷新设置为 O_DIRECT。
然而,PostgreSQL 数据库并不支持 O_DIRECT,所以 PG 存在数据库性能抖动的问题,无法在海量互联网业务中使用。
然而,什么是 O_DIRECT 呢?
相信很多同学会说,O_DIRECT 是指文件读写时,数据直接访问磁盘,而不要经过操作系统的缓存。
嗯,这个没有错,但 show me your code 。
接着,Java 开发工程师、DBA 们就一脸茫然了。
估计你让一个 P8 工程师来,也写不出。
不信?那你问问身边的工程师们。
O_DIRECT 原理本身不特别复杂,一看即懂,一句话就能说清。
但这个特性却非常小众,按我的理解只存在于类似数据库的开发领域。
绝大部分业务的开发工程师们,与文件打交道就是打印日志。
日志打印主要目的是性能,不需要 O_DIRECT 。日志数据由于缓存写,若发生丢失,丢就丢了吧。
甚至,Java 语言本身都没提供 O_DIRECT 的文件选项。若想使用,还需要自己额外进行一层底层的封装。
好吧,接着让姜老师写个最简单的 demo :
这个 demo 就是向文件 f.test 写入16384个字节。
可以看到,这里 open 的时候加入了额外的 O_DIRECT 选项,接着通过 pwrite 函数将数据写入文件。
但这里需要特别注意的是 O_DIRECT 写入,要求内存地址与扇区大小对齐。下面是官方文档的说明:
因此,你会看到下面这两行用于处理内存对齐的逻辑:
buf = (char*)malloc(sizeof(char*)*PAGE_SIZE*2);
buf_aligned = (char*)ut_align(buf,SECTOR_SIZE); // align address for DIRECT_IO
只有做了地址对齐,才能使用 O_DIRECT,否则 pwrite 后的 assert 校验就会失败。
但扇区大小是多少呢?文档的说法就相当玄幻了:
文档的意思大致就是扇区大小是可变化的,而且也没有提供一个统一的接口去获取文件系统的扇区大小。
根据经验,我们知道大部分磁盘的扇区大小是 512 字节,SSD 的扇区大小是 4K。
因此,若要使用 O_DIRECT ,建议直接按 4K 对齐,这样就无需关注下面的具体存储类型了(至少目前好像还没有扇区大小超过 4K 的设备)。
细心的同学会发现,在上面的代码中,使用 O_DIRECT 后,还需要进行 fsync 这又是为什么呢?
是的,使用 O_DIRECT 选项后,文件写入时会绕过操作系统缓存,数据直接落盘:
从上图可以看到使用 O_DIRECT 选项后,磁盘读写从文件系统层直接访问最底层的存储设备,不走操作系统层的 Page Cache。
但即便使用 O_DIRECT ,在写入后,还是需要通过调用一次 fsync 用于保证数据真正落到磁盘。
这是因为文件对应的元数据信息还没有落盘,例如文件的大小,最后的修改时间等。
但是,若文件没有增长呢?只是更新了一个页的数据。
是的,那这时就无需在写入文件后,再进行 fsync 操作。这样可进一步提升磁盘性能。
MySQL 5.7.25 版本开始,就进行了类似这样的优化,对参数 innodb_flush_method 提供了新的选项 O_DIRECT_NO_FSYNC 。看文档的说明:
今天姜老师深入讲解了 O_DIRECT 的使用,这是一个文件系统操作非常底层的使用选项,一般仅用于数据库中。
今天留下2道思考题,相信答对者年薪百万那是妥妥的:
MySQL InnoDB存储引擎刷新磁盘使用 O_DIRECT,他是根据多少大小进行字节对齐的呢?
为什么重做日志文件写入却不需要启用 O_DIRECT 选项呢?
RAW格式是否还有性能优势呢?
直播预告
往期推荐
一个参数,MySQL 8.0 性能飙升180%!!!
全网首测,MySQL Router来了,不容错过!!!
MySQL 8.0,二进制日志的一大改进!
02集 | MySQL崛起:起飞
01集 | MySQL崛起:缘起